{/* Copyright 2020 Adobe. All rights reserved.
This file is licensed to you under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. You may obtain a copy
of the License at http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
OF ANY KIND, either express or implied. See the License for the specific language
governing permissions and limitations under the License. */}

import {Layout} from '@react-spectrum/docs';
export default Layout;

import docs from 'docs:@react-aria/checkbox';
import hiddenDocs from 'docs:@react-aria/visually-hidden';
import focusDocs from 'docs:@react-aria/focus';
import statelyDocs from 'docs:@react-stately/checkbox';
import {HeaderInfo, FunctionAPI, TypeContext, InterfaceType, TypeLink, PageDescription} from '@react-spectrum/docs';
import {Keyboard} from '@react-spectrum/text';
import packageData from '@react-aria/checkbox/package.json';
import Anatomy from './checkboxgroup-anatomy.svg';
import {ExampleCard} from '@react-spectrum/docs/src/ExampleCard';
import buttongroupPreview from 'url:./buttongroup-example.png';

---
category: Forms
keywords: [checkbox, input, aria]
after_version: 3.1.0
---

# useCheckboxGroup

<PageDescription>{docs.exports.useCheckboxGroup.description}</PageDescription>

<HeaderInfo
  packageData={packageData}
  componentNames={['useCheckboxGroup', 'useCheckboxGroupItem']}
  sourceData={[
    {type: 'W3C', url: 'https://www.w3.org/WAI/ARIA/apg/patterns/checkbox/'}
  ]} />

## API

<FunctionAPI function={docs.exports.useCheckboxGroup} links={docs.links} />
<FunctionAPI function={docs.exports.useCheckboxGroupItem} links={docs.links} />

## Features

Checkbox groups can be built in HTML with the
[&lt;fieldset&gt;](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/fieldset)
and [&lt;input&gt;](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input) elements,
however these can be difficult to style. `useCheckboxGroup` and `useCheckboxGroupItem` help achieve accessible
checkbox groups that can be styled as needed.

* Checkbox groups are exposed to assistive technology via ARIA
* Each checkbox is built with a native HTML `<input>` element, which can be optionally visually
  hidden to allow custom styling
* Full support for browser features like form autofill and validation
* Keyboard focus management and cross browser normalization
* Group and checkbox labeling support for assistive technology

## Anatomy

<Anatomy />

A checkbox group consists of a set of checkboxes, and a label. Each checkbox
includes a label and a visual selection indicator. Zero or more checkboxes
within the group can be selected at a time. Users may click or touch a checkbox
to select it, or use the <Keyboard>Tab</Keyboard> key to navigate to it
and the <Keyboard>Space</Keyboard> key to toggle it.

`useCheckboxGroup` returns props for the group and its label, which you should spread
onto the appropriate element:

<TypeContext.Provider value={docs.links}>
  <InterfaceType properties={docs.links[docs.exports.useCheckboxGroup.return.id].properties} />
</TypeContext.Provider>

`useCheckboxGroupItem` returns props for an individual checkbox:

<TypeContext.Provider value={docs.links}>
  <InterfaceType properties={docs.links[docs.exports.useCheckboxGroupItem.return.id].properties} />
</TypeContext.Provider>

Selection state is managed by the <TypeLink links={statelyDocs.links} type={statelyDocs.exports.useCheckboxGroupState} />
hook in `@react-stately/checkbox`. The state object should be passed as an option to `useCheckboxGroup`
and `useCheckboxGroupItem`.

Individual checkboxes must have a visual label. If the checkbox group does not have a visible label,
an `aria-label` or `aria-labelledby` prop must be passed instead to identify the element to assistive
technology.

**Note:** `useCheckboxGroupItem` should only be used when it is contained within a checkbox group. For a
standalone checkbox, use the [useCheckbox](../Checkbox/useCheckbox.html) hook instead.

## Example

This example uses native input elements for the checkboxes, and React context to share state from the group
to each checkbox. An HTML `<label>` element wraps the native input and the text to provide an implicit label
for the checkbox.

```tsx example export=true
import {useCheckboxGroup, useCheckboxGroupItem} from '@react-aria/checkbox';
import {useCheckboxGroupState} from '@react-stately/checkbox';

let CheckboxGroupContext = React.createContext(null);

function CheckboxGroup(props) {
  let {children, label, description} = props;
  let state = useCheckboxGroupState(props);
  let {groupProps, labelProps, descriptionProps, errorMessageProps, isInvalid, validationErrors} = useCheckboxGroup(props, state);

  return (
    <div {...groupProps}>
      <span {...labelProps}>{label}</span>
      <CheckboxGroupContext.Provider value={state}>
        {children}
      </CheckboxGroupContext.Provider>
      {description && <div {...descriptionProps} style={{fontSize: 12}}>{description}</div>}
      {isInvalid &&
        <div {...errorMessageProps} style={{color: 'red', fontSize: 12}}>{validationErrors.join(' ')}</div>
      }
    </div>
  );
}

function Checkbox(props) {
  let {children} = props;
  let state = React.useContext(CheckboxGroupContext);
  let ref = React.useRef(null);
  let {inputProps, labelProps} = useCheckboxGroupItem(props, state, ref);

  let isDisabled = state.isDisabled || props.isDisabled;
  let isSelected = state.isSelected(props.value);

  return (
    <label
      {...labelProps}
      style={{
        display: 'block',
        color: (isDisabled && 'var(--gray)') || (isSelected && 'var(--blue)'),
      }}>
      <input {...inputProps} ref={ref} />
      {children}
    </label>
  );
}

<CheckboxGroup label="Favorite sports">
  <Checkbox value="soccer" isDisabled>Soccer</Checkbox>
  <Checkbox value="baseball">Baseball</Checkbox>
  <Checkbox value="basketball">Basketball</Checkbox>
</CheckboxGroup>
```

## Styling

See the [useCheckbox](../Checkbox/useCheckbox.html#styling) docs for details on how to customize the styling of checkbox elements.

## Styled examples

<ExampleCard
  url="https://codesandbox.io/s/magical-bose-l7z36b?file=/src/ButtonGroup.js"
  preview={buttongroupPreview}
  title="Button Group"
  description="A multi-selectable segmented ButtonGroup component." />

## Usage

The following examples show how to use the `CheckboxGroup` component created in the above example.

### Default value

An initial, uncontrolled value can be provided to the CheckboxGroup using the `defaultValue` prop, which accepts an array of selected items that map to the
`value` prop on each Checkbox.

```tsx example
<CheckboxGroup label="Favorite sports (uncontrolled)" defaultValue={['soccer', 'baseball']}>
  <Checkbox value="soccer">Soccer</Checkbox>
  <Checkbox value="baseball">Baseball</Checkbox>
  <Checkbox value="basketball">Basketball</Checkbox>
</CheckboxGroup>
```

### Controlled value

A controlled value can be provided using the `value` prop, which accepts an array of selected items, which map to the
`value` prop on each Checkbox. The `onChange` event is fired when the user checks or unchecks an option. It receives a new array
containing the updated selected values.

```tsx example
function Example() {
  let [selected, setSelected] = React.useState(['soccer', 'baseball']);

  return (
    <CheckboxGroup label="Favorite sports (controlled)" value={selected} onChange={setSelected}>
      <Checkbox value="soccer">Soccer</Checkbox>
      <Checkbox value="baseball">Baseball</Checkbox>
      <Checkbox value="basketball">Basketball</Checkbox>
    </CheckboxGroup>
  );
}
```

### Description

The `description` prop can be used to associate additional help text with a checkbox group.

```tsx example
<CheckboxGroup label="Favorite sports" description="Select your favorite sports.">
  <Checkbox value="soccer">Soccer</Checkbox>
  <Checkbox value="baseball">Baseball</Checkbox>
  <Checkbox value="basketball">Basketball</Checkbox>
</CheckboxGroup>
```

### Group validation

CheckboxGroup supports the `isRequired` prop to ensure the user selects at least one item, as well as custom client and server-side validation. Individual checkboxes also support validation, and errors from all checkboxes are aggregated at the group level. CheckboxGroup can also be integrated with other form libraries. See the [Forms](../forms) guide to learn more.

When a CheckboxGroup has the `validationBehavior="native"` prop, validation errors block form submission. The `isRequired` prop at the `CheckboxGroup` level requires that at least one item is selected. To display validation errors, use the `validationErrors` and `errorMessageProps` returned by `useCheckboxGroup`. This allows you to render error messages from all of the above sources with consistent custom styles.

```tsx example
<form>
  <CheckboxGroup
    label="Sandwich condiments"
    name="condiments"
    /*- begin highlight -*/
    isRequired
    validationBehavior="native"
    /*- end highlight -*/
  >
    <Checkbox value="lettuce">Lettuce</Checkbox>
    <Checkbox value="tomato">Tomato</Checkbox>
    <Checkbox value="onion">Onion</Checkbox>
    <Checkbox value="sprouts">Sprouts</Checkbox>
  </CheckboxGroup>
  <input type="submit" style={{marginTop: 8}} />
</form>
```

### Individual Checkbox validation

To require that specific checkboxes are checked, set the `isRequired` prop at the `Checkbox` level instead of the `CheckboxGroup`. The following example shows how to require that all items are selected.

```tsx example
<form>
  <CheckboxGroup label="Agree to the following" validationBehavior="native">
    {/*- begin highlight -*/}
    <Checkbox value="terms" isRequired>Terms and conditions</Checkbox>
    <Checkbox value="privacy" isRequired>Privacy policy</Checkbox>
    <Checkbox value="cookies" isRequired>Cookie policy</Checkbox>
    {/*- end highlight -*/}
  </CheckboxGroup>
  <input type="submit" style={{marginTop: 8}} />
</form>
```

### Disabled

The entire CheckboxGroup can be disabled with the `isDisabled` prop.

```tsx example
<CheckboxGroup label="Favorite sports" isDisabled>
  <Checkbox value="soccer">Soccer</Checkbox>
  <Checkbox value="baseball">Baseball</Checkbox>
  <Checkbox value="basketball">Basketball</Checkbox>
</CheckboxGroup>
```

To disable an individual checkbox, pass `isDisabled` to the `Checkbox` instead.

```tsx example
<CheckboxGroup label="Favorite sports">
  <Checkbox value="soccer">Soccer</Checkbox>
  <Checkbox value="baseball" isDisabled>Baseball</Checkbox>
  <Checkbox value="basketball">Basketball</Checkbox>
</CheckboxGroup>
```

### Read only

The `isReadOnly` prop makes the selection immutable. Unlike `isDisabled`, the CheckboxGroup remains focusable.
See the [MDN docs](https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/readonly) for more information.

```tsx example
<CheckboxGroup label="Favorite sports" defaultValue={['baseball']} isReadOnly>
  <Checkbox value="soccer">Soccer</Checkbox>
  <Checkbox value="baseball">Baseball</Checkbox>
  <Checkbox value="basketball">Basketball</Checkbox>
</CheckboxGroup>
```

### HTML forms

CheckboxGroup supports the `name` prop, paired with the Checkbox `value` prop, for integration with HTML forms.

```tsx example
<CheckboxGroup label="Favorite sports" name="sports">
  <Checkbox value="soccer">Soccer</Checkbox>
  <Checkbox value="baseball">Baseball</Checkbox>
  <Checkbox value="basketball">Basketball</Checkbox>
</CheckboxGroup>
```
